/* vim: set sw=8 ts=8 sts=8 expandtab: */
#include <Cmaid.h>
#include "cmaid_private.h"

static Cmaid_Cache *cmaid_stringcache = NULL;
static int cmaid_stringcache_init_count = 0;

/**
 * @defgroup Cmaid_Stringcache The Stringcache
 * @ingroup Misc
 *
 * These functions allow you to store one copy of a string, and use it
 * throughout your program.
 *
 * This is a method to reduce the number of duplicated strings kept in
 * memory. It's pretty common for the same strings to be dynamically
 * allocated repeatedly between applications and libraries, especially in
 * circumstances where you could have multiple copies of a structure that
 * allocates the string. So rather than duplicating and freeing these
 * strings, you request a read-only pointer to an existing string and
 * only incur the overhead of a hash lookup.
 *
 * It sounds like micro-optimizing, but profiling has shown this can have
 * a significant impact as you scale the number of copies up. It improves
 * string creation/destruction speed, reduces memory use and decreases
 * memory fragmentation, so a win all-around.
 *
 */

/**
 * @return  Zero on failure, non-zero on successful initialization.
 * @brief Initialize the cmaid stringcache internal structure.
 */
EAPI int 
cmaid_stringcache_init()
{
        /*
         * No strings have been loaded at this point, so create the hash
         * table for storing string info for later.
         */
        if (!cmaid_stringcache_init_count)
                cmaid_stringcache = cmaid_hash_cache_new(&cmaid_value_inline_string);

        cmaid_stringcache_init_count++;
        return 1;
}

/**
 * @param str The string to retrieve an instance of.
 * @return A pointer to an instance of the string on success.
 *          @c NULL on failure.
 * @brief Retrieves an instance of a string for use in a program.
 */
EAPI const char *
cmaid_stringcache_instance(const char *str)
{
        if (!cmaid_stringcache)
                return NULL;

        return cmaid_cache_instance(cmaid_stringcache, str);
}

/**
 * @param str The given string.
 * @brief Notes that the given string has lost an instance.
 *
 * It will free the string if no other instances are left.
 */
EAPI void
cmaid_stringcache_release(const char *str)
{
        if (!cmaid_stringcache)
                return;

        cmaid_cache_release(cmaid_stringcache, str);
}

/**
 * @brief Shutdown the stringcache internal structures
 *
 * Frees the internal stringcache, if it isn't used elsewhere. In other words
 *
 */
EAPI void 
cmaid_stringcache_shutdown(void)
{
        --cmaid_stringcache_init_count;
        if (!cmaid_stringcache_init_count)
        {
                cmaid_container_destroy(cmaid_stringcache);
                cmaid_stringcache = NULL;
        }
}
